use std::{
    iter::Sum,
    ops::{Add, Div, Mul, Neg, Sub},
    // os::unix::ucred::impl_linux,
};

#[derive(Clone, Copy, Debug)]
pub struct Vector<const N: usize, T>(pub [T; N])
where
    T: Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T> + PartialOrd + Default;

pub type Vec2<T> = Vector<2, T>;
pub type Vec3<T> = Vector<3, T>;
pub type Vec4<T> = Vector<4, T>;

pub type Vec2f = Vector<2, f32>;
pub type Vec3f = Vector<3, f32>;
pub type Vec4f = Vector<4, f32>;

pub type Vec2i = Vector<2, isize>;
pub type Vec3i = Vector<3, isize>;
pub type Vec4i = Vector<4, isize>;

// pub type Vec2u = Vector<2, usize>;
// pub type Vec3u = Vector<3, usize>;
// pub type Vec4u = Vector<4, usize>;

/// 列向量
pub struct Matrix<const N: usize, T>(pub [Vector<N, T>; N])
where
    T: Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T> + PartialOrd + Default;

pub type Mat2<T> = Matrix<2, T>;
pub type Mat3<T> = Matrix<3, T>;
pub type Mat4<T> = Matrix<4, T>;

pub type Mat2f = Matrix<2, f32>;
pub type Mat3f = Matrix<3, f32>;
pub type Mat4f = Matrix<4, f32>;

pub type Mat2i = Matrix<2, isize>;
pub type Mat3i = Matrix<3, isize>;
pub type Mat4i = Matrix<4, isize>;

// pub type Mat2u = Matrix<2, usize>;
// pub type Mat3u = Matrix<3, usize>;
// pub type Mat4u = Matrix<4, usize>;

// From
impl<const N: usize, T> From<[T; N]> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    fn from(n: [T; N]) -> Self {
        Self(n)
    }
}

// impl<const N: usize, const M: usize, T> From<&Vector<M, T>> for Vector<N, T>
// where
//     T: Add<Output = T>
//         + Mul<Output = T>
//         + Sub<Output = T>
//         + Div<Output = T>
//         + PartialOrd
//         + Default
//         + Copy,
// {
//     fn from(other: &Vector<M, T>) -> Self {
//         // let min_len: usize = if N < M { N } else { M }; //M.min(N);
//         const min_len: &usize = if N < M { N } else { M }; //M.min(N);

//         // let v = vec![];
//         let v = [T::default(); min_len];
//         v.reserve(min_len);
//         for i in 0..min_len {
//             v[i] = other.0[i];
//         }
//         // let b = v.into_boxed_slice();
//         Self(v)
//     }
// }
// default
impl<const N: usize, T> Default for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    fn default() -> Self {
        Self([T::default(); N])
    }
}
// Element wise

// Add T
impl<const N: usize, T> Add<T> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn add(self, rhs: T) -> Self::Output {
        // fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] + rhs;
        }
        Self(n)
    }
}

// Sub T
impl<const N: usize, T> Sub<T> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn sub(self, rhs: T) -> Self::Output {
        // fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] - rhs;
        }
        Self(n)
    }
}

// Mul T
impl<const N: usize, T> Mul<T> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn mul(self, rhs: T) -> Self::Output {
        // fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] * rhs;
        }
        Self(n)
    }
}
// Div T
impl<const N: usize, T> Div<T> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn div(self, rhs: T) -> Self::Output {
        // fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] / rhs;
        }
        Self(n)
    }
}

//
// vector wise
//

// Add Vector
impl<const N: usize, T> Add<Vector<N, T>> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn add(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] + rhs.0[i];
        }
        Self(n)
    }
}
// Mul Vector
impl<const N: usize, T> Mul<Vector<N, T>> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] * rhs.0[i];
        }
        Self(n)
    }
}
// Sub Vector
impl<const N: usize, T> Sub<Vector<N, T>> for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn sub(self, rhs: Vector<N, T>) -> Self::Output {
        let mut n = [T::default(); N];
        for i in 0..N {
            n[i] = self.0[i] - rhs.0[i];
        }
        Self(n)
    }
}
///
///general perpose
///
impl<const N: usize, T> Neg for Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + Neg<Output = T>
        + PartialOrd
        + Default
        + Copy
        + Sum,
{
    type Output = Vector<N, T>;
    fn neg(self) -> Self::Output {
        Vector::from(self.0.map(|e| -e))
    }
}
impl<const N: usize, T> Vector<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy
        + Sum,
{
    // type Element = T;
    pub fn dot(&self, rhs: &Vector<N, T>) -> T {
        self.0.iter().zip(rhs.0.iter()).map(|(a, b)| *a + *b).sum()
    }
    // pub fn truncate(&self) -> Vector<{ N - 1 }, T> {  }
    pub fn extend(&self) -> Vector<{ N + 1 }, T> {
        let mut k = Vector::default();
        // let mut k = Vector::from();
        self.0.iter().enumerate().for_each(|(i, &v)| k.0[i] = v);
        k
    }
}
impl Vec3f {
    // normalize self
    pub fn normalize(self) -> Self {
        let sqrt_sum: f32 = self.0.iter().sum();
        // let sqrt_sum = self.0.iter().fold(0.0, |accum, item| accum + item);
        self / sqrt_sum.sqrt()
    }
    pub fn unit_y() -> Self {
        [0.0, 1.0, 0.0f32].into()
    }
}

///
/// Special cases
///

impl<T> Vector<2, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    pub fn perp_dot(&self, rhs: Vector<2, T>) -> T {
        self.0[0] * rhs.0[1] - self.0[1] * rhs.0[0]
    }
}

//
// Matrix Operators
//
impl<const N: usize, T> Default for Matrix<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    fn default() -> Self {
        Self([Vector::default(); N])
    }
}

impl<const N: usize, T> From<[[T; N]; N]> for Matrix<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    fn from(_: [[T; N]; N]) -> Self {
        Self::default()
    }
}

impl<const N: usize, T> Mul<Vector<N, T>> for Matrix<N, T>
where
    T: Add<Output = T>
        + Mul<Output = T>
        + Sub<Output = T>
        + Div<Output = T>
        + PartialOrd
        + Default
        + Copy,
{
    type Output = Vector<N, T>;
    fn mul(self, rhs: Vector<N, T>) -> Self::Output {
        self.0
            .zip(rhs.0)
            .map(|(v, a)| v * a)
            .iter()
            .fold(Vector::default(), |accum, &v| accum + v)
    }
}
impl Vec3f {
    pub fn x(&self) -> f32 {
        self.0[0]
    }
    pub fn y(&self) -> f32 {
        self.0[1]
    }
    pub fn z(&self) -> f32 {
        self.0[2]
    }
    pub fn cross(&self, other: &Self) -> Self {
        Self([
            (self.y() * other.z()) - (self.z() * other.y()),
            (self.z() * other.x()) - (self.x() * other.z()),
            (self.x() * other.y()) - (self.y() * other.x()),
        ])
    }
}
impl Mat4f {
    pub fn one() -> Self {
        Self([
            Vector::from([1.0f32, 0.0, 0.0, 0.0]),
            Vector::from([0.0f32, 1.0, 0.0, 0.0]),
            Vector::from([0.0f32, 0.0, 1.0, 0.0]),
            Vector::from([0.0f32, 0.0, 0.0, 1.0]),
        ])
    }
    fn perspective() {}
    fn rotate_around() {}
    // right hand coordination view transform
    pub fn view_rh(look_from: Vec3f, look_at: Vec3f, up: Vec3f) -> Self {
        todo!("src/maths.rs: test view_rh() function");
        let res = Self::one();

        let f = (look_at - look_from).normalize();
        let s = f.cross(&up);
        let u = s.cross(&f);
        let f = Vec3f::from((look_at - look_from).normalize()).extend();
        let s = Vec3f::from(s).extend();
        let u = Vec3f::from(u).extend();

        let tran = -look_at.extend();
        tran.0[3] = 1.0;
        let mut trans = Self::one();
        trans.0[3] = tran;
        // let s =
        // Self::default()
        Self::from([f.0, s.0, u.0, tran.0])
    }
}
